<script setup>
import { ref, onMounted, reactive } from "vue";
import * as d3 from "d3";
import { zoom, zoomIdentity } from "d3-zoom";
import axios from "axios";

const canvasRef = ref(null);
const state = reactive({
  hoverColor: "black",
  tooltipTitleColor: null,
});
onMounted(() => {
  getInitD3();
});

const open = async () => {
  location.href = "weixin://dl/business/?t=b4VB5aySQGq";
};

const getInitD3 = async () => {
  try {
    const [res, percentageData] = await Promise.all([
      axios.get("https://tu.h0.cn/d3.json"),
      axios.get("https://tu.h0.cn/data.json"),
    ]);
    function cleanData(node) {
      if (Array.isArray(node.children)) {
        node.children.forEach(cleanData);
      } else {
        node.children = Object.entries(node.children); // 将 null 替换为 []
      }
    }
    const width = 1442;
    const height = 821;
    const color = d3.scaleSequential([8, 0], d3.interpolateMagma);
    const treeData = processTreemapData(res.data, percentageData.data);

    console.log(treeData);
    // const totalValue = d3.sum(treeData, (d) => d.scale);
    // const logScale = d3
    //   .scaleLog()
    //   .domain([1, d3.max(treeData.children, (d) => d.scale)]) // 输入范围
    //   .range([1, 1]); // 输出的缩放范围

    const treemap = (data) =>
      d3
        .treemap()
        .size([width, height])
        .paddingOuter(1)
        .paddingTop(20)
        .paddingInner(1)
        .round(true)
        .tile(d3.treemapBinary)(d3.hierarchy(data).sum((d) => d.scale / 1e9));
    const root = treemap(treeData);
    console.log(treeData);
    const canvas = d3
      .select(canvasRef.value)
      .attr("width", width)
      .attr("height", height);

    const context = canvas.node().getContext("2d");
    let currentTransform = d3.zoomIdentity;

    function render() {
      context.save();
      context.clearRect(0, 0, width, height);

      context.translate(currentTransform.x, currentTransform.y);
      context.scale(currentTransform.k, currentTransform.k);

      root.each((d) => {
        context.beginPath();
        context.rect(d.x0, d.y0, d.x1 - d.x0, d.y1 - d.y0);
        //最内层
        if (d.depth >= 3) {
          context.fillStyle = d.data.itemStyle?.color || "black";
          context.fill();
          context.lineWidth = 0.2;
          context.strokeStyle = "black";
          context.stroke();
        } else if (d.depth >= 2) {
          context.height = 1;
          context.fillStyle = d.data.itemStyle?.borderColor
            ? d.data.itemStyle?.borderColor
            : color(d.height);
          context.fill();
          context.strokeStyle = "black";
          context.stroke();
        } else {
          context.fillStyle = "black";
          context.fill();
          context.strokeStyle = "white";
          context.stroke();
        }
        //小于xxx不显示文字
        if (d.x1 - d.x0 > 10 && d.y1 - d.y0 > 5) {
          context.save();
          context.clip();
          context.fillStyle = "white";
          context.font = `${Math.min((d.x1 - d.x0) / 10, (d.y1 - d.y0) / 5, 10)}px sans-serif`;
          d.depth >= 3
            ? context.fillText(
                d.data.name + "/" + d.data.percentage,
                d.x0 + 3,
                d.y0 + 13,
              )
            : context.fillText(d.data.name, d.x0 + 3, d.y0 + 13);
          context.restore();
        }
      });

      context.restore();
    }

    render();
    const zoom = d3
      .zoom()
      .scaleExtent([1, 3]) // 设置缩放范围
      .on("zoom", (event) => {
        const newTransform = event.transform;
        console.log(newTransform);
        // 如果缩放比例为1，则禁止平移
        if (newTransform.k === 1) {
          newTransform.x = 0;
          newTransform.y = 0;
        }

        currentTransform = newTransform;
        render();
      });

    canvas.call(zoom);

    // Add event listeners for tooltip
    canvas.on("mousemove", (event) => {
      const [x, y] = d3.pointer(event);
      const node = findNode(
        root,
        x / currentTransform.k - currentTransform.x / currentTransform.k,
        y / currentTransform.k - currentTransform.y / currentTransform.k,
      );
      if (node) {
        showTooltip(node, event.pageX, event.pageY);
      } else {
        hideTooltip();
      }
    });

    canvas.on("mouseout", hideTooltip);
  } catch (error) {
    console.error("图表加载错误:", error);
  }
};

function findNode(node, x, y) {
  if (x < node.x0 || x > node.x1 || y < node.y0 || y > node.y1) {
    return null;
  }
  if (node.children) {
    for (let child of node.children) {
      const found = findNode(child, x, y);
      if (found) return found;
    }
  }
  return node;
}

function showTooltip(node, x, y) {
  if (node.depth < 2) {
    hideTooltip();
    return;
  }
  let data = node.depth >= 3 ? node.parent?.children : node.children;
  let itemWithCode1 =
    data.find((item) => item.data.code === node.data.code) || null;
  itemWithCode1 = itemWithCode1 || data[0];
  state.tooltipTitleColor = itemWithCode1?.data.itemStyle?.color;
  if (itemWithCode1) {
    data = [itemWithCode1].concat(
      data.filter((item) => item !== itemWithCode1),
    );
  }
  const tooltip = d3.select("#tooltip");
  tooltip
    .style("display", "block")
    .style("left", `${x + 10}px`)
    .style("top", `${y + 10}px`)
    .html(
      data
        .map(
          (child) => `
    <div class="tooltip-item" >
      <strong>${child.data.name}</strong><br>
      Scale: ${child.data.scale}<br>
      ${child.data.percentage ? `Percentage: ${child.data.percentage}%` : ""}
     </div>`,
        )
        .join(""),

      //       `
      //   <strong>${node.data.name}</strong><br>
      //   Scale: ${node.data.scale}<br>
      //   ${node.data.percentage ? `Percentage: ${node.data.percentage}%` : ''}
      // `
    );
}

function hideTooltip() {
  d3.select("#tooltip").style("display", "none");
}
const getColor = (percentage) => {
  const colorMap = [
    { range: ">=4", color: "#e41813" },
    { range: ">=3", color: "#be1207" },
    { range: ">=2", color: "#960f0f" },
    { range: ">=1", color: "#6d1414" },
    { range: "<=-4", color: "#28d742" },
    { range: "<=-3", color: "#1da548" },
    { range: "<=-2", color: "#106f2f" },
    { range: "<=-1", color: "#0a5421" },
    { range: "default", color: "#424454" },
  ];

  for (const item of colorMap) {
    if (
      (item.range === ">=4" && percentage >= 4) ||
      (item.range === ">=3" && percentage >= 3) ||
      (item.range === ">=2" && percentage >= 2) ||
      (item.range === ">=1" && percentage >= 1) ||
      (item.range === "<=-4" && percentage <= -4) ||
      (item.range === "<=-3" && percentage <= -3) ||
      (item.range === "<=-2" && percentage <= -2) ||
      (item.range === "<=-1" && percentage <= -1) ||
      item.range === "default"
    ) {
      return item.color;
    }
  }
};
const getPercentage = (code, percentageData) => {
  if (!code || !percentageData[code]) return null;
  const value = percentageData[code].split("|")[1];
  return parseFloat(value);
};
const processTreemapData = (data, percentageData) => {
  function transformNode(node, level = 0) {
    const result = {
      ...node,
      name: node.name,
      code: node.code,
      value: node.scale,
    };

    if (node.children && node.children.length > 0) {
      result.children = node.children.map((child) =>
        transformNode(child, level + 1),
      );
      result.itemStyle = {
        borderColor: result.children[0].itemStyle.color,
      };
    } else if (node.code) {
      const percentage = getPercentage(node.code, percentageData);
      if (percentage !== null) {
        result.percentage = percentage;
        result.itemStyle = {
          color: getColor(percentage) || "black",
        };
      }
    }

    return result;
  }

  return {
    ...data,
    children: data.children.map((item) => ({
      name: item.name,
      children: item.children
        ? item.children.map((child) => transformNode(child, 0))
        : undefined,
    })),
  };
};
</script>

<template>
  <div class="overflow-hidden">
    <div class="chart-container">
      <canvas ref="canvasRef"></canvas>
      <div id="tooltip" class="tooltip" style="display: none"></div>
    </div>
  </div>
  <!--  <div @click="open" class="legend-container">测试</div>-->
</template>

<style lang="scss">
.chart-container {
  position: relative;
}

.tooltip {
  width: 180px;
  position: absolute;
  background-color: white;
  color: black;
  border-radius: 3px;
  font-size: 12px;
  pointer-events: none;
  border: 5px solid #000;
}
//选择第一个
.tooltip-item:first-child {
  padding: 5px 0;
  color: white;
  background-color: v-bind("state.tooltipTitleColor");
}
</style>
